package org.qiyu.live.web.starter.context;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.qiyu.live.web.starter.error.QiYuErrorException;
import org.qiyu.live.web.starter.limit.RequestLimit;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2023-10-22
 * Time: 20:53
 */
public class RequestLimitInterceptor implements HandlerInterceptor {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${spring.application.name}")
    private String applicationName;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            boolean annotationPresent = handlerMethod.getMethod().isAnnotationPresent(RequestLimit.class);
            if (annotationPresent) {// 必须要加上这个注解
                // 对userId进行限流
                Long userId = QiyuRequestContext.getUserId();
                if (userId == null) {
                    return true;
                }
                String key = applicationName + ":" + request.getRequestURI() + ":" + userId;
                RequestLimit requestLimit = handlerMethod.getMethod().getAnnotation(RequestLimit.class);
                int limit = requestLimit.limit();
                String msg = requestLimit.msg();
                int second = requestLimit.second();
                int reqTime = (Integer) Optional.ofNullable(redisTemplate.opsForValue().get(key)).orElse(0);
                if (reqTime == 0) {
                    redisTemplate.opsForValue().increment(key, 1);
                    redisTemplate.expire(key, second, TimeUnit.SECONDS);
                    return true;
                }
                if (reqTime < limit) {
                    redisTemplate.opsForValue().increment(key, 1);
                    return true;
                }
                throw new QiYuErrorException(-1, msg);
            }
        }
        return true;
    }
}